#include "chimage.h"

ChImage::ChImage(QString filename)
{
    //初始化空指针
    fileHeader=(BITMAPFILEHEADER *)malloc(sizeof (BITMAPFILEHEADER));
    infoHeader=(BITMAPINFOHEADER *)malloc(sizeof (BITMAPINFOHEADER));
    //构造qfile对象,并且读出各种基础数据
    chFile=new QFile(filename);
    chFile->open( QFile::ReadOnly );
    qDebug() <<"sizeofBimapfileheader: "<<sizeof (BITMAPFILEHEADER)<<endl;
    qDebug() <<"SIZEOFBITMAPFILEHEADER:"<<sizeof (tagBITMAPFILEHEADER)<<endl;

    QByteArray arr=chFile->read(sizeof (tagBITMAPFILEHEADER));
    QByteArray arr2=chFile->read(sizeof (tagBITMAPINFOHEADER));
    memcpy(fileHeader,arr,sizeof (tagBITMAPFILEHEADER));
    memcpy(infoHeader,arr2,sizeof (tagBITMAPINFOHEADER));

    qDebug() <<"sizeof getImageSizeBy width and length: "<<sizeof (BYTE)<<endl;
    qDebug() <<"tongshang:"<<getSizeByAttributes()*sizeof (BYTE)<<endl;

    //按照文件头提供的信息初始化数据结构，将图片内容读入数据结构
    chBytes=(BYTE*)malloc(getSizeByAttributes()*sizeof (BYTE));
    QByteArray arr4;
    chFile->seek(getOffBits());
    for(int i=0;i<getSizeByAttributes();i++){
        arr4=chFile->read(sizeof (BYTE));
        memcpy(&chBytes[i],arr4,sizeof (BYTE));
        qDebug() <<i<<" th BYTE memcpyed successfully."<<endl;
    }
    //qDebug() <<"biSizeImage: "<<getImageSize()<<endl;
}
ChImage::ChImage(std::string filename){
}
int ChImage::getImageHeight(){
    return infoHeader->biHeight;
}
int ChImage::getImageWidth(){
    return infoHeader->biWidth;
}
int ChImage::getFileSize(){
    return fileHeader->bfSize;
}
int ChImage::getBitCount(){
    return infoHeader->biBitCount;
}
int ChImage::getImageSize(){
    return infoHeader->biSizeImage;
}
int ChImage::getOffBits(){
    return fileHeader->bfOffBits;
}
bool ChImage::checkImage(){
    return fileHeader->bfType==19778;
}
int ChImage::getSizeByAttributes(){
    return getImageWidth()*getImageHeight()*getBitCount()/8;
}

void ChImage::toAdd(int type){

    srand((int)time(0));                        //获取随机种子
    int numOfArr = getSizeByAttributes();       //数组长度
    int num = (numOfArr / 100) + 1;    //令百分之一的像素产生噪声
    int numOfPixel = 0;                         //像素个数

    switch (type) {
    case 8:                                     //如果是灰度图
        numOfPixel = numOfArr;
        for(int i = 0; i < num; i++){
            int index = random(numOfPixel);   //获得随机数作为下标
            int bORw = random(2);                          //随机产生椒噪声或盐噪声

            if(bORw == 0){                                 //若是椒噪声
                for(int j = 0; j < 8; j++){
                     CLR_BYTE(chBytes[index], j);
                }
            }else{                                         //若是盐噪声
                for(int j = 0; j < 8; j++){
                    SET_BYTE(chBytes[index], j);
                }
            }
        }

        break;
    case 24:                                     //如果是24色真彩图
        numOfPixel = numOfArr / 3;           //计算多少个像素
        for(int i = 0; i < numOfPixel; i++){
            int index1 = random(numOfPixel) * 3;      //每个像素取3BYTE数据
            int index2 = index1 + 1;
            int index3 = index1 + 2;
            int bORw = random(2);

            if(bORw == 0){
                for(int j = 0; j < 8; j++){
                     CLR_BYTE(chBytes[index1], j);
                }
                for(int j = 0; j < 8; j++){
                     CLR_BYTE(chBytes[index2], j);
                }
                for(int j = 0; j < 8; j++){
                     CLR_BYTE(chBytes[index3], j);
                }
            }else{
                for(int j = 0; j < 8; j++){
                    SET_BYTE(chBytes[index1], j);
                }
                for(int j = 0; j < 8; j++){
                    SET_BYTE(chBytes[index2], j);
                }
                for(int j = 0; j < 8; j++){
                    SET_BYTE(chBytes[index3], j);
                }
            }
        }

        break;
    default:
        break;
    }
}

void ChImage::addNoise(){
    int type = getBitCount();
    int number = getSizeByAttributes();
    for(int i = 0; i < number; i++){
        qDebug() << chBytes[i];
    }
    toAdd(type);
    for(int i = 0; i < number; i++){
        qDebug() << chBytes[i];
    }
}

void ChImage::insert(char* msg){                      //图片信息插入方法

    BYTE *insert = (unsigned char*) msg;              //把要插入的信息从char*转换成byte*
    int length = strlen(msg);                         //计算byte*长度，即几个字节
    int hasSave = 0;                                  //该变量为已经存储了多少bit数据

//    for(int k = 0; k < length * 8; k++){
//        for(int m = 0; m < 8; m++){
//            int b = GET_BYTE(chBytes[k], m);
//            qDebug() << b;
//        }
//        qDebug() << endl;
//    }

    for(int i = 0; i < length; i++){                  //每个字节
        for(int j = 0; j < 8; j++){                   //有8bit数据需要存储
            int x = GET_BYTE(insert[i], j);           //获取该字节的第j个位数据
//            qDebug() << x;
            if(x == 0){                               //若为0，则将其写入chbyte[hasSave]的最后一位
                CLR_BYTE(chBytes[hasSave], 7);
                hasSave++;
            }else{
                SET_BYTE(chBytes[hasSave], 7);        //为1同理
                hasSave++;
            }
        }
    }
//    for(int k = 0; k < length * 8; k++){
//        for(int m = 0; m < 8; m++){
//            int b = GET_BYTE(chBytes[k], m);
//            qDebug() << b;
//        }
//        qDebug() << endl;
//    }
}

void ChImage::extract(){
    int length = getSizeByAttributes();
    int yu = length % 8;
    int out_length = 0;

    int *ple = new int[length + yu];

    for(int i = 0; i < length; i++){
        ple[i] = GET_BYTE(chBytes[i], 7);
//        qDebug() << ple[i];
    }
    if(yu != 0){
        for(int i = 0; i < yu; i++){
            ple[length + i] = 0;
        }
    }

    if(yu == 0){
        out_length = length / 8;
    }else{
        out_length = length / 8 + 1;
    }
    char *out = new char[out_length];
    qDebug() << out_length;
    for(int i = 0; i < out_length; i++){
        int input = 0;
        for(int j = 0; j < 8; j++){
            input += ple[i * 8 + j] * pow(2, 7 - j);
        }
//        qDebug() << input;
        out[i] = input;
        qDebug() << out[i];
    }
    hasExtract = out;
}

bool ChImage::save(QString filename){
    //建立文件输入流
    QFile file(filename);
    file.open(QFile::WriteOnly);
    QDataStream out(&file);
    out.writeRawData((char *)fileHeader,sizeof (BITMAPFILEHEADER));
    out.writeRawData((char *)infoHeader,sizeof (BITMAPINFOHEADER));
    //file.seek(getOffBits());
    out.writeRawData((char *)chBytes,getSizeByAttributes()*sizeof (char));

    qDebug() <<sizeof (BITMAPINFOHEADER)<<sizeof (BITMAPFILEHEADER)<<"written"<<endl;
    file.flush();
    file.close();
    return true;
}
